package com.netintech.project.system.rtsp.udp;

import com.netintech.common.utils.CollectionUtils;
import com.netintech.project.system.rtsp.RTSPClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
public class UDPReceiver {

    private static final int LISTENING_PORT = 16264;
    private static final int BUFFER_SIZE = 1024 * 10;

    private static NumberFormat numberFormat;

    static {
        numberFormat = NumberFormat.getInstance();
        numberFormat.setGroupingUsed(false);
        // 设置精确到小数点后2位
        numberFormat.setMaximumFractionDigits(2);
    }


    public static void main(String[] args) throws Exception {
        byte[] buffer = new byte[BUFFER_SIZE];
        DatagramPacket msg = new DatagramPacket(buffer, buffer.length);

        try (DatagramSocket socket = new DatagramSocket(LISTENING_PORT)) {
            log.info("udp接收端已经启动");
            while (true) {
                // 接收数据包
                socket.receive(msg);
                String msgBody = new String(
                        msg.getData(), msg.getOffset(), msg.getLength());
                // 发现接收的消息是空，便跳出循环
                if (msgBody.isEmpty()) {
                    break;
                }

                int senderPort = msg.getPort();
                InetAddress senderAddr = msg.getAddress();

                System.out.printf("发送端 地址和端口 -> (%s:%d)\n",
                        senderAddr.getHostAddress(), senderPort);

                System.out.println("发送端 发送的消息 -> " + msgBody + "\n");
            }
        }

        System.out.println("接收端已经关闭。");
    }

    /**
     * 接收消息，获取序列数
     *
     * @param listeningPort
     */
    public static void receive(int listeningPort, RTSPClient rtspClient) {
        List<Integer> sequenceNumList = new ArrayList<>();
        byte[] buffer = new byte[BUFFER_SIZE];
        DatagramPacket msg = new DatagramPacket(buffer, buffer.length);
        try (DatagramSocket socket = new DatagramSocket(listeningPort)) {
            socket.setSoTimeout(2000);
            while (true) {
                if (rtspClient.getShutdown()) {
                    System.out.println("rtspClient.getShutdown().get()");
                    socket.close();
                    break;
                }
                // 接收数据包
                socket.receive(msg);
//                InetAddress senderAddr = msg.getAddress();
//            int senderPort = msg.getPort();
//                log.info("发送端 地址和端口 -> " + senderAddr.getHostAddress() + ":" + senderPort);
//                log.info("udp接收端已经启动");

                String msgBody = new String(
                        msg.getData(), msg.getOffset(), msg.getLength());
//                log.info("发送端 发送的消息 -> " + msgBody + "\n");

                byte[] data = msg.getData();
                // 发现接收的消息是空，便跳出循环
                if (StringUtils.isBlank(msgBody)) {
                    socket.close();
                    break;
                }
                int sequenceNum = getSequenceNum(data);
                log.info("索引数-->" + sequenceNum);
                sequenceNumList.add(sequenceNum);
            }
            log.info("udp接收端已经关闭。");
        } catch (Exception e) {
            log.error("udp接收端连接失败", e);
        } finally {
            computePacketLossRate(sequenceNumList);
        }
    }

    /**
     * 计算丢包率
     *
     * @param sequenceNumList
     * @return
     */
    private static String computePacketLossRate(List<Integer> sequenceNumList) {
        List<Integer> packetLoss = new ArrayList<>();
        int packetLossCount = 0;
        if (CollectionUtils.isEmpty(sequenceNumList)) {
            return "索引数集合为空";
        }
//        先排序
        sequenceNumList.sort(Integer::compare);
        for (int i = 0; i < sequenceNumList.size() - 1; i++) {
            if (sequenceNumList.get(i + 1) - sequenceNumList.get(i) > 1) {
                packetLoss.add(sequenceNumList.get(i));
                packetLoss.add(sequenceNumList.get(i + 1));
                packetLossCount += sequenceNumList.get(i + 1) - sequenceNumList.get(i);
            }
        }
        String packetLossRate = numberFormat.format((double) packetLossCount / sequenceNumList.size() * 100) + "%";
        System.out.println("丢包率为" + packetLossRate);
        return packetLossRate;
    }

    /**
     * 截取字节数组2-3字节，转换成数字
     *
     * @param data
     * @return
     */
    private static int getSequenceNum(byte[] data) {
        byte[] b = new byte[2];
        System.arraycopy(data, 2, b, 0, 2);
        return bytesToshort(b);
    }


    public static int bytesToshort(byte[] src) {
        return (src[0] << 8 & 0xFF00) | (src[1] & 0xFF);
    }


}